/****************************************************************************
 *   Copyright (C) 2008 by 7552                                             *
 *   fiubataller2-08c1@gruposyahoo.com.ar                                   *
 *                                                                          *
 *  Licensed under the Apache License, Version 2.0 (the "License");         *
 *  you may not use this file except in compliance with the License.        *
 *  You may obtain a copy of the License at                                 *
 *                                                                          *
 *      http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                          *
 *  Unless required by applicable law or agreed to in writing, software     *
 *  distributed under the License is distributed on an "AS IS" BASIS,       *
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 *  See the License for the specific language governing permissions and     *
 *  limitations under the License.                                          *
 *                                                                          *
 ***************************************************************************/


#ifndef __RECORD_H__
#define __RECORD_H__


#include <fstream>
#include <map>
#include <vector>
#include <list>
#include "errorCodes.h"

using namespace std;

namespace Taller2
{
namespace TransRec
{

enum LogEntryType { NONE = 0x0, INSERT, UPDATE, DELETE, COMMIT, ROLLBACK, CHECKPOINT };
const int OFFSET_TO_TRANSACTIONID = 3*sizeof(int) + sizeof(LogEntryType);

/**
	\brief Clase abstracta base de todos los registros.
	Esta clase es usada como interface.
*/
class CLogRecord
{
protected:
		LogEntryType m_EntryType;
		int 		 m_LSN;
		int 		 m_LastLSN;
		int 		 m_timestamp;
public:

	/**
	*/
	static int CreateRecord(fstream &f, CLogRecord* &record);

	/**
	*/
	CLogRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de tipo \b et, y con timestamp pasado como parametro.
		\param et Tipo del registro.
		\param timestamp Timestamp del nuevo registro.
	*/
	CLogRecord(LogEntryType et, int timestamp);

	/**
	*/
	virtual int Load(fstream& f, bool allocStates = false);

	/**
		\brief Devuelve el tipo de registro.
		\return Tipo del registro.
	*/
	LogEntryType EntryType(){ return m_EntryType;};

	/**
		\brief Devuelve el timestamp del registro.
		\return timestamp del registro.
	*/
	int TimeStamp(){return m_timestamp;};

	/**
		\brief Devuelve el LSN del registro.
		\return LSN del registro
	*/
	int GetLSN(){return m_LSN;};

	/**
		\brief Asigna el valor \b value a LSN.
		\param value Nuevo valor de LSN
	*/
	void SetLSN(int value){m_LSN = value;};

	/**
		\brief Devuelve el LastLSN del registro.
		\return LastLSN del registro.
	*/
	int LastLSN(){return m_LastLSN;};

	/**
		\brief Asigna el valor \b value a LastLSN
		\param value Nuevo valor de LastLSN.
	*/
	void LastLSN(int value){m_LastLSN = value;};

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer){return NO_ERROR;};

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f){return NO_ERROR;};
};

//*******************************************************************
/**
	Clase que encapsula a un registro de CHECKPOINT.
*/
class CCheckPointRecord : public CLogRecord
{
public:
	typedef map<int,int> CheckpointMap;

protected:
	CheckpointMap m_tansList;
public:

	/**
	*/
	CCheckPointRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de CHECKPOINT con timestamp pasado como parametro.
		\param timestamp Timestamp del nuevo registro.
	*/
	CCheckPointRecord(int timestamp);

	/**
		\brief Destructor de la clase.
	*/
	~CCheckPointRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de CHECKPOINT a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
	*/
	virtual int Load(fstream& f, bool allocStates = false);

	/**
		\brief Agrega el ID y el LSN de una transacci�n abierta en el registro.
		\param TransactionID ID de la transacci�n.
		\param TransactionLSN LSN de la transacci�n.
	*/
	void addTransaction(int TransactionID, int TransactionLSN);

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer);

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f);

	/**
	*/
	CheckpointMap GetTransactionMap();
};

//*******************************************************************

/**
	Clase base de todas las operaciones relacionadas con una
	transacci�n: UPDATE, INSERT, DELETE, ROLLBACK y COMMIT.
*/

class CBasicOperationRecord : public CLogRecord
{
protected:
	int m_lastLSNsameTransaction;
	int m_TransactionID;
public:

	/**
	*/
	CBasicOperationRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de tipo \b et, y con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param et Tipo del registro.
		\param timestamp Timestamp del nuevo registro.
	*/
	CBasicOperationRecord( int ID, LogEntryType et, int timestamp);

	/**
	*/
	virtual int Load(fstream& f, bool allocStates = false) = 0;

	/**
		\brief Devuelve el valor del ID de transacci�n del registro.
		\return ID de transacci�n del registro.
	*/
	int TransactionID(){return m_TransactionID;};

	/**
		\brief Devuelve el valor de LSN del registro anterior de la misma transacci�n.
		\return valor de LSN del registro anterior de la misma transacci�n.

	*/
	int LastLSNSameTransaction(){return m_lastLSNsameTransaction;};

	/**
		\brief Asigna el valor de LSN del registro anterior de la misma transacci�n.
		\param value Valor de LSN a asignar.
	*/
	void LastLSNSameTransaction(int value) {m_lastLSNsameTransaction = value;};

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer);

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f);
};

//*******************************************************************

/**
	Clase que encapsula a un registro de COMMIT.
*/
class CCommitRecord : public CBasicOperationRecord
{
public:

	/**
	*/
	CCommitRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de COMMIT, con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param timestamp Timestamp del nuevo registro.
	*/
	CCommitRecord( int ID, int timestamp);


	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de COMMIT a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
	*/
	virtual int Load(fstream &f, bool allocStates = false);
};

//*******************************************************************

/**
	Clase que encapsula a un registro de ROLLBACK.
*/
class CRollbackRecord : public CBasicOperationRecord
{
public:

	/**
	*/
	CRollbackRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de ROLLBACK, con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param timestamp Timestamp del nuevo registro.
	*/
	CRollbackRecord( int ID, int timestamp);

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de ROLLBACK a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
	*/
	virtual int Load(fstream &f, bool allocStates);
};

//*******************************************************************

/**
	Clase que encapsula a un registro de INSERT.
*/
class CInsertRecord : public CBasicOperationRecord
{
protected:
	long long  m_ObjectID;
	int m_NewObjectSize;
	char* m_Object;

public:
	/**
	*/
	CInsertRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de INSERT, con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param timestamp Timestamp del nuevo registro.
		\param ObjectID ID del objeto a insertar.
		\param objectSize Tama�o del objeto a insertar.
		\param object bloque de memoria conteniendo el objeto serializado.
	*/
	CInsertRecord(int ID, int timestamp, long long  ObjectID);

	/**
		\brief Destructor de la clase.
	*/
   ~CInsertRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de INSERT a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
		\param allocObject Si �ste parametro es \b true, el constructor recupera la serializaci�n del objecto. Si es \b false, no.
	*/
	virtual int Load(fstream &f, bool allocStates = false);

   	/**
	*/
	int SetState(const char* object, int objectSize);

	/**
		\brief Devuelve el objecto a insertar serializado.
		\return Direcci�n del bloque de memoria con la serializaci�n del objeto.
	*/
   const char* Object() {return m_Object;};

	/**
		\brief Tama�o en bytes del bloque de memoria devuelto por Object().
		\return Tama�o en bytes.
	*/
   int ObjectSize() {return m_NewObjectSize;};

	/**
		\brief Devuelve el ID del objeto a insertar.
		\return ID del objeto.
	*/
   long long ObjectID(){ return m_ObjectID;};

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer);

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f);
};

//***************************************************************************
/**
	Clase que encapsula a un registro de DELETE.
*/
class CDeleteRecord : public CBasicOperationRecord
{
protected:
	long long  m_ObjectID;
	int m_oldObjectSize;
	char* m_Object;

public:
	/**
	*/
	CDeleteRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de DELETE, con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param timestamp Timestamp del nuevo registro.
		\param ObjectID ID del objeto a borrar.
		\param objectSize Tama�o del objeto a borrar.
		\param object bloque de memoria conteniendo el objeto serializado.
	*/
	CDeleteRecord(int ID, int timestamp, long long  ObjectID);

	/**
		\brief Destructor de la clase.
	*/
   ~CDeleteRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de DELETE a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
		\param allocObject Si �ste parametro es \b true, el constructor recupera la serializaci�n del objecto. Si es \b false, no.
	*/
	virtual int Load(fstream& f, bool allocStates = false);

   /**
   */
   int SetState(const char* object, int objectSize);

	/**
		\brief Devuelve el objecto a borrar serializado.
		\return Direcci�n del bloque de memoria con la serializaci�n del objeto.
	*/
   const char* Object() {return m_Object;};

	/**
		\brief Tama�o en bytes del bloque de memoria devuelto por Object().
		\return Tama�o en bytes.
	*/
   int ObjectSize() {return m_oldObjectSize;};

	/**
		\brief Devuelve el ID del objeto a insertar.
		\return ID del objeto.
	*/
   long long  ObjectID(){ return m_ObjectID;};

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer);

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f);
};

//***************************************************************************
/**
	Clase que encapsula a un registro de UPDATE.
*/
class CUpdateRecord : public CBasicOperationRecord
{
protected:
	long long m_ObjectID;
	int m_newObjectSize;
	int m_oldObjectSize;
	char* m_newObject;
	char* m_oldObject;

public:
	/**
	*/
	CUpdateRecord();

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de UPDATE, con timestamp pasado como parametro.
		\param ID ID de la transacci�n.
		\param timestamp Timestamp del nuevo registro.
		\param ObjectID ID del objeto a modificar.
		\param newObjectSize Tama�o del objeto modificado.
		\param newObject bloque de memoria conteniendo el objeto serializado modificado.
		\param oldObjectSize Tama�o del objeto antes de ser modificado.
		\param oldObject bloque de memoria conteniendo el objeto serializado antes de ser modificado.
	*/
	CUpdateRecord(int ID, int timestamp, long long ObjectID);

	/**
		\brief Destructor de la clase
	*/
   ~CUpdateRecord();

   /**
   */
	int SetState(const char* oldObject, int oldObjectSize,
				 const char* newObject, int newObjectSize);

	/**
		\brief Constructor de la clase.
		Crea un nuevo registro de UPDATE a partir del stream f.
		\param f stream utilizado para acceder al archivo. Debe estar abierto y el cursor apuntando al comienzo del registro.
		\param allocObject Si �ste parametro es \b true, el constructor recupera la serializaci�n del objecto. Si es \b false, no.
	*/
	virtual int Load(fstream& f, bool allocStates = false);

	/**
		\brief Devuelve la serializaci�n del objeto modificado.
		\return Direcci�n del bloque de memoria con la serializaci�n del objeto.
	*/
	const char* NewObject() {return m_newObject;};

	/**
		\brief Tama�o en bytes del bloque de memoria devuelto por NewObject().
		\return Tama�o en bytes.
	*/
	int NewObjectSize() {return m_newObjectSize;};

	/**
		\brief Devuelve la serializaci�n del objeto antes de ser modificado.
		\return Direcci�n del bloque de memoria con la serializaci�n del objeto.
	*/
	const char* OldObject() {return m_oldObject;};

	/**
		\brief Tama�o en bytes del bloque de memoria devuelto por OldObject().
		\return Tama�o en bytes.
	*/
	int OldObjectSize() {return m_oldObjectSize;};

	/**
		\brief Devuelve el ID del objeto a insertar.
		\return ID del objeto.
	*/
	long long ObjectID(){ return m_ObjectID;};

	/**
		\brief Devuelve el valor tama�o del registro serializado.
		\return tama�o en bytes.
	*/
	virtual size_t getSize();

	/**
		\brief Devuelve el registro serializado en un bloque de memoria.
		\return Direcci�n del bloque de memoria donde el registro est� serializado. Devuelve 0 si se produce alg�n error.
	*/
	virtual int serialize(char* &pBuffer);

	/**
		\brief Escrbie el registro al final del stream f.
		\param  f stream utilizado para acceder al archivo. Debe estar abierto y el cursor no es devuelto a su posici�n inicial.
		\return \b true si el registro se puede grabar exitosamente. Sino devuelve \b false.
	*/
	virtual int appendToFile(fstream &f);
};

typedef list<CLogRecord*> TLogRecordVector;

}
}

#endif
